package com.example.gateway.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 定义的 Spring Cloud Gateway 全局过滤器（GlobalFilter），用于统一拦截所有经过 Gateway 的请求，并记录请求耗时日志。
 * GlobalFilter：表示这是一个全局过滤器，对所有路由都生效。
 * Ordered：实现该接口可以设置执行顺序（通过 getOrder() 方法）。
 */
@Slf4j
@Component
public class RtGlobalFilter implements GlobalFilter, Ordered {

    /**
     * 过滤器的主逻辑方法，作用于每个请求和响应过程。
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        /**
         * 获取当前 HTTP 请求对象；
         * 获取请求的完整 URL；
         * 记录请求开始时间；
         * 输出日志。
         * 这部分是前置处理逻辑，在请求被转发前执行。
         */
        ServerHttpRequest request = exchange.getRequest(); // 请求对象
        String uri = request.getURI().toString(); // 请求地址
        long start = System.currentTimeMillis(); // 记录开始时间
        log.info("请求 {} 开始，时间为：{}", uri, start);
        /**
         * 以上为前置逻辑
         */
        /**
         * chain.filter(exchange) 表示将请求继续传递给下一个过滤器或目标服务；
         * doFinally() 是 Reactor 提供的钩子，用于无论成功或失败都执行某段逻辑；
         * end - start 表示请求总耗时，记录到日志中。
         * 这部分是后置处理逻辑，在响应返回之后执行。
         */
        /**
         * 返回值 Mono<Void> 表示异步处理，返回 null 表示同步处理。
         */
        return chain.filter(exchange)
                .doFinally(result -> {
                    /**
                     * 以下为后置逻辑
                     */
                    long end = System.currentTimeMillis();
                    log.info("请求 {} 结束，耗时：{}ms", uri, end - start);
                });
    }

    /**
     * 过滤器执行顺序：值越小，优先级越高
     * Gateway 会根据返回的整数决定过滤器执行顺序；
     * 数字越小，优先级越高；
     * 通常建议：
     * 全局日志：设置为 -1 ~ 0
     * 鉴权、限流等：设置为 1 ~ 10
     * 最后执行的设置为较大值（如 100）
     */
    @Override
    public int getOrder() {
        return 0;
    }

}
